package com.sishu.njrtsdms.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sishu.njrtsdms.domain.dto.TcpDeclareBelongYearConfigDTO;
import com.sishu.njrtsdms.domain.vo.TcpDeclareBelongYearConfigVO;
import com.sishu.njrtsdms.exception.ServiceException;
import com.sishu.njrtsdms.jooq.codegen.tables.daos.TcpDeclareBelongYearConfigDAO;
import com.sishu.njrtsdms.jooq.codegen.tables.pojos.TcpDeclareBelongYearConfig;
import com.sishu.njrtsdms.service.TcpDeclareBelongYearConfigService;
import lombok.SneakyThrows;
import org.jooq.types.ULong;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

import static com.sishu.njrtsdms.jooq.codegen.Tables.TBL_TCP_DECLARE_BELONG_YEAR_CONFIG;

/**
 * 重点建设项目申报所属年度配置业务实现类
 */
@Service
public class TcpDeclareBelongYearConfigServiceImpl implements TcpDeclareBelongYearConfigService {
    private final TcpDeclareBelongYearConfigDAO tcpDeclareBelongYearConfigDAO;

    public TcpDeclareBelongYearConfigServiceImpl(TcpDeclareBelongYearConfigDAO tcpDeclareBelongYearConfigDAO) {
        this.tcpDeclareBelongYearConfigDAO = tcpDeclareBelongYearConfigDAO;
    }

    @Override
    public List<TcpDeclareBelongYearConfigVO> listTcpDeclareBelongYearConfigs() {
        return tcpDeclareBelongYearConfigDAO.listTcpDeclareBelongYearConfigs();
    }

    @Override
    public void addNewDeclareBelongYearConfig(TcpDeclareBelongYearConfigDTO tcpDeclareBelongYearConfigDTO) {
        var tcpDeclareBelongYearConfigForInsert = fromDtoToPojo(tcpDeclareBelongYearConfigDTO);
        checkTcpDeclareBelongYearConfig(tcpDeclareBelongYearConfigForInsert, false);
        tcpDeclareBelongYearConfigDAO.insertSelective(tcpDeclareBelongYearConfigForInsert);

    }


    @Override
    public void UpdateDeclareBelongYearConfig(ULong tcpDbycId, TcpDeclareBelongYearConfigDTO tcpDeclareBelongYearConfigDTO) {
        var tcpDeclareBelongYearConfigForUpdate = fromDtoToPojo(tcpDeclareBelongYearConfigDTO);
        checkTcpDeclareBelongYearConfig(tcpDeclareBelongYearConfigForUpdate, true);
        tcpDeclareBelongYearConfigDAO.updateSelective(tcpDeclareBelongYearConfigForUpdate);
    }


    @SneakyThrows
    private TcpDeclareBelongYearConfig fromDtoToPojo(TcpDeclareBelongYearConfigDTO tcpDeclareBelongYearConfigDTO) {
        TcpDeclareBelongYearConfig tcpDeclareBelongYearConfig = new TcpDeclareBelongYearConfig();
        tcpDeclareBelongYearConfig.setTcpDbycId(tcpDeclareBelongYearConfigDTO.tcpDbycId());
        tcpDeclareBelongYearConfig.setBelongYear(tcpDeclareBelongYearConfigDTO.belongYear());
        tcpDeclareBelongYearConfig.setDeclareBeginDateTime(tcpDeclareBelongYearConfigDTO.declareBeginDateTime());
        tcpDeclareBelongYearConfig.setDeclareEndDateTime(tcpDeclareBelongYearConfigDTO.declareEndDateTime());
        tcpDeclareBelongYearConfig.setGpaAssignableBeginDateTime(tcpDeclareBelongYearConfigDTO.gpaAssignableBeginDateTime());
        tcpDeclareBelongYearConfig.setGpaAssignableEndDateTime(tcpDeclareBelongYearConfigDTO.gpaAssignableEndDateTime());
        tcpDeclareBelongYearConfig.setRemark(tcpDeclareBelongYearConfigDTO.remark());
        return tcpDeclareBelongYearConfig;
    }

    private void checkTcpDeclareBelongYearConfig(TcpDeclareBelongYearConfig
                                                         tcpDeclareBelongYearConfig,
                                                 boolean isForUpdate) {

        var declareBeginDateTime = tcpDeclareBelongYearConfig.getDeclareBeginDateTime();
        var declareEndDateTime = tcpDeclareBelongYearConfig.getDeclareEndDateTime();
        var gpaAssignableBeginDateTime = tcpDeclareBelongYearConfig.getGpaAssignableBeginDateTime();
        var gpaAssignableEndDateTime = tcpDeclareBelongYearConfig.getGpaAssignableEndDateTime();
        var tcpDbycId = tcpDeclareBelongYearConfig.getTcpDbycId();

        // 无论修改还是新增,绩点时间段的起始日期时间必须大于申报截止日期
        LocalDateTime targetDeclareEndDateTime = declareEndDateTime;
        // 修改时,校验除自身以外的所有时间段
        List<TcpDeclareBelongYearConfig> tcpDeclareBelongYearConfigs;
        if (isForUpdate) {
            if (ObjectUtil.isAllEmpty(
                    declareBeginDateTime,
                    declareEndDateTime,
                    gpaAssignableBeginDateTime,
                    gpaAssignableEndDateTime)) return;

            if ((declareBeginDateTime == null && declareEndDateTime != null)
                    ||
                    (declareBeginDateTime != null && declareEndDateTime == null)
                    ||
                    (gpaAssignableBeginDateTime == null && gpaAssignableEndDateTime != null)
                    ||
                    (gpaAssignableBeginDateTime != null && gpaAssignableEndDateTime == null)
            ) throw new ServiceException("修改配置时,任何时间段中的起始或截止日期时间都不可单独存在");

            var tcpDeclareBelongYearConfigDB = tcpDeclareBelongYearConfigDAO
                    .fetchOneByTcpDbycId(tcpDbycId);
            if (tcpDeclareBelongYearConfigDB == null)
                throw new ServiceException("修改的配置不存在或已删除");
            if (declareBeginDateTime == null)
                targetDeclareEndDateTime = tcpDeclareBelongYearConfigDB.getDeclareEndDateTime();

            var condition = TBL_TCP_DECLARE_BELONG_YEAR_CONFIG.TCP_DBYC_ID
                    .ne(tcpDbycId);
            tcpDeclareBelongYearConfigs = tcpDeclareBelongYearConfigDAO
                    .fetch(condition, TBL_TCP_DECLARE_BELONG_YEAR_CONFIG.BELONG_YEAR.asc());
        } else {
            // 新增时,校验所有现存时间段
            tcpDeclareBelongYearConfigs = tcpDeclareBelongYearConfigDAO.findAll();
        }
        // 起始时间要小于截止时间
        if ((declareBeginDateTime != null && !declareBeginDateTime.isBefore(declareEndDateTime))
                ||
                (gpaAssignableBeginDateTime != null && !gpaAssignableBeginDateTime.isBefore(gpaAssignableEndDateTime))
        ) throw new ServiceException("任何时间段配置起始时间必须要小于截止日期时间");

        // 绩点分配时间段的起始日期时间不早于申报起始日期时间即可
        if (gpaAssignableBeginDateTime != null
                &&
                (gpaAssignableBeginDateTime.isAfter(targetDeclareEndDateTime)))
            throw new ServiceException("绩点分配时间段的起始日期不可早于申报起始日期");

        // 为null时为修改,则一定为修改绩点分配时间段,则无需考虑与其他时间段冲突问题
        if (declareBeginDateTime == null)
            return;
        // 判断是否与其他现存时间段冲突
        tcpDeclareBelongYearConfigs
                .stream()
                .filter(it -> {
                    var existDeclareBeginDateTime = it.getDeclareBeginDateTime();
                    var existDeclareEndDateTime = it.getDeclareEndDateTime();
                    return LocalDateTimeUtil.isIn(
                            declareBeginDateTime,
                            existDeclareBeginDateTime,
                            existDeclareEndDateTime
                    );
                })
                .findAny()
                .ifPresent(it -> {
                    throw new ServiceException(
                            StrUtil.format("配置申报起始日期时间不能在任何现存的配置时间段中," +
                                            "冲突的配置的归属年度为:[{}]," +
                                            "申报起始日期时间为:[{}]," +
                                            "申报截止日期时间为:[{}],",
                                    it.getBelongYear(),
                                    it.getDeclareBeginDateTime(),
                                    it.getDeclareEndDateTime()));
                });
    }
}
